home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / news / nntp / nntp.1.5.11 / server / serve.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-01-10  |  9.9 KB  |  494 lines

  1. #ifndef lint
  2. static char    *sccsid = "@(#)$Header: serve.c,v 1.37 91/01/10 17:19:52 sob Exp $";
  3. #endif
  4.  
  5. /*
  6.  * Main server routine
  7.  */
  8.  
  9. #include "common.h"
  10. #include <signal.h>
  11. #ifdef USG
  12. #include <sys/times.h>
  13. #else
  14. #include <sys/time.h>
  15. #endif
  16.  
  17. #ifdef LOG
  18. # ifndef USG
  19. #  include <sys/resource.h>
  20. # endif not USG
  21. #endif
  22.  
  23. #ifdef TIMERS
  24. #include "timer.h"
  25. #endif
  26.  
  27. extern    int    ahbs(), group(), help(), ihave();
  28. extern    int    list(), newgroups(), newnews(), nextlast(), post();
  29. extern    int    slave(), stat(), xhdr();
  30.  
  31. extern int errno;
  32.  
  33. #ifdef AUTH
  34. extern    int    doauth();
  35. #endif AUTH
  36.  
  37. static struct cmdent {
  38.     char    *cmd_name;
  39.     int    authreq;    /* 0=none,1=userpass */
  40.     int    (*cmd_fctn)();
  41. } cmdtbl[] = {
  42. #ifdef AUTH
  43.     "authcap",    0,    doauth,
  44.     "authinfo",    0,    doauth,
  45.     "authsys",    0,    doauth,
  46. #endif AUTH
  47.     "article",    0,    ahbs,
  48.     "body",        0,    ahbs,
  49.     "group",    0,    group,
  50.     "head",        0,    ahbs,
  51.     "help",        0,    help,
  52.     "ihave",    1,    ihave,
  53.     "last",        0,    nextlast,
  54.     "list",        0,    list,
  55.     "newgroups",    0,    newgroups,
  56.     "newnews",    0,    newnews,
  57.     "next",        0,    nextlast,
  58.     "post",        1,    post,
  59.     "slave",    0,    slave,
  60.     "stat",        0,    ahbs,
  61. #ifdef XHDR
  62.     "xhdr",        0,    xhdr,
  63. #endif XHDR
  64. };
  65. #define NUMCMDS (sizeof(cmdtbl) / sizeof(struct cmdent))
  66.  
  67. #ifdef TIMEOUT
  68. static void timeout();
  69. #endif
  70. #ifdef LOGINCHECK
  71. static void logincheck();
  72. static int firstlogincheck;
  73. #endif
  74. #ifdef BATCHED_INPUT
  75. static void batchcheck();
  76. #endif
  77.  
  78. #ifdef TIMERS
  79. static struct timer timers[] = {
  80. #ifdef TIMEOUT
  81.     { timeout, 1, TIMEOUT, 0 },
  82. #endif
  83. #ifdef LOGINCHECK
  84.     { logincheck, 0, LOGINCHECK, 0 },
  85. #endif
  86. #ifdef BATCHCHECK
  87.     { batchcheck, 1, BATCHCHECK, 0 },
  88. #endif
  89. };
  90. #define NTIMERS (sizeof(timers) / sizeof(struct timer))
  91. #endif
  92.  
  93. static char *stats_init();
  94. #ifdef LOG
  95. static void stats_finish();
  96. #endif
  97.  
  98. #ifdef AUTH
  99. extern int    Needauth;
  100. extern char    User[];
  101. #endif AUTH
  102.  
  103. /*
  104.  * serve -- given a connection on stdin/stdout, serve
  105.  *    a client, executing commands until the client
  106.  *    says goodbye.
  107.  *
  108.  *    Parameters:    None.
  109.  *
  110.  *    Returns:    Exits.
  111.  *
  112.  *    Side effects:    Talks to client, does a lot of
  113.  *            stuff.
  114.  */
  115.  
  116. serve()
  117. {
  118.     char        line[NNTP_STRLEN];
  119.     char        host[MAXHOSTNAMELEN];
  120.     char        gdbuf[MAXBUFLEN];
  121.     char        **argp;
  122.     char        *timeptr, *cp;
  123.     int        argnum, i;
  124. #ifdef POSTER
  125.     struct passwd    *pp;
  126. #endif
  127. #ifdef LOG
  128.     grps_acsd = arts_acsd = 0;
  129. #endif
  130.  
  131.     /* Not all systems pass fd's 1 and 2 from inetd */
  132.  
  133.     (void) close(1);
  134.     (void) close(2);
  135.     (void) dup(0);
  136.     (void) dup(0);
  137.  
  138.     /* If we're ALONE, then we've already opened syslog */
  139.  
  140. #ifndef ALONE
  141. # ifdef SYSLOG
  142. #  ifdef BSD_42
  143.     openlog("nntpd", LOG_PID);
  144. #  else
  145.     openlog("nntpd", LOG_PID, SYSLOG);
  146. #  endif
  147. # endif
  148. #endif
  149.  
  150.     timeptr = stats_init();
  151.  
  152. #ifdef ALONE
  153. #ifndef USG
  154.     (void) signal(SIGCHLD, SIG_IGN);
  155. #endif not USG
  156. #endif
  157.  
  158.     /* Ignore SIGPIPE, since we'll see closed connections with read */
  159.  
  160.     (void) signal(SIGPIPE, SIG_IGN);
  161.  
  162.     /* Get permissions and see if we can talk to this client */
  163. #ifdef AUTH
  164.     Needauth = 1;
  165.     strcpy(User,"");
  166. #endif AUTH
  167.     host_access(&canread, &canpost, &canxfer, gdbuf);
  168.  
  169.     if (gethostname(host, sizeof(host)) < 0)
  170.         (void) strcpy(host, "Amnesiac");
  171.  
  172. #ifdef SETPROCTITLE
  173.     setproctitle("%s", hostname);
  174. #endif
  175.  
  176.     if (!canread && !canxfer) {
  177.         printf("%d %s NNTP server can't talk to you.  Goodbye.\r\n",
  178.             ERR_ACCESS, host);
  179.         (void) fflush(stdout);
  180.         (void) fclose(stdout);
  181. #ifdef SYSLOG
  182.         syslog(LOG_INFO, "%s refused connection", hostname);
  183. #endif
  184.         exit(1);
  185.     }
  186.  
  187. #ifdef LOGINCHECK
  188.     firstlogincheck = 1;
  189.     logincheck();
  190.     firstlogincheck = 0;
  191. #endif
  192.  
  193.     if ( !canpost && !canread && !space(MINFREE)) {
  194.         printf("%d %s NNTP server out of space. Try later.\r\n",
  195.             ERR_GOODBYE, host);
  196.         (void) fflush(stdout);
  197. #ifdef SYSLOG
  198.         syslog(LOG_INFO, "%s no space", hostname);
  199. #endif
  200.         exit(1);
  201.     }
  202.  
  203.     /* If we can talk, proceed with initialization */
  204.  
  205.     ngpermcount = get_nglist(&ngpermlist, gdbuf);
  206.  
  207. #ifdef POSTER
  208.     pp = getpwnam(POSTER);
  209.     if (pp != NULL) {
  210.         uid_poster = pp->pw_uid;
  211.         gid_poster = pp->pw_gid;
  212.         home_poster = pp->pw_dir;
  213.     } else
  214. #endif
  215.         uid_poster = gid_poster = 0;
  216.  
  217. #ifndef FASTFORK
  218.     num_groups = 0;
  219.     num_groups = read_groups();    /* Read in the active file */
  220. #else
  221.     signal(SIGALRM, SIG_IGN);    /* Children don't deal with */
  222.                     /* these things */
  223. #endif
  224.     /*
  225.      * num_groups may be zero if expire is running and the active
  226.      * file is locked. (Under System V with lockf, for example.)
  227.      * Or, something may be really screwed up....
  228.      */
  229.     if (num_groups == 0){ /* can't get a group list */
  230.         printf("%d %s NNTP server unavailable. Try later.\r\n",
  231.             ERR_FAULT, host);
  232.         (void) fflush(stdout);
  233. #ifdef SYSLOG
  234.         syslog(LOG_INFO, "%s no groups", hostname);
  235. #endif
  236.         exit(1);
  237.     }
  238.  
  239.     art_fp = NULL;
  240.     argp = (char **) NULL;        /* for first time */
  241.  
  242.     if ((cp = index(timeptr, '\n')) != NULL)
  243.         *cp = '\0';
  244.     else
  245.         timeptr = "Unknown date";
  246. #ifdef AUTH
  247.     printf("%d %s NNTP[auth] server version %s ready at %s (%s).\r\n",
  248. #else
  249.     printf("%d %s NNTP server version %s ready at %s (%s).\r\n",
  250. #endif
  251.         canpost ? OK_CANPOST : OK_NOPOST,
  252.         host, nntp_version,
  253.         timeptr,
  254.         canpost ? "posting ok" : "no posting");
  255.     (void) fflush(stdout);
  256.  
  257.     /*
  258.      * Now get commands one at a time and execute the
  259.      * appropriate routine to deal with them.
  260.      */
  261. #ifdef TIMERS
  262.     timer_init(timers, NTIMERS);
  263. #endif
  264.     for (;;) {
  265. #ifdef TIMERS
  266.         /* Don't try to read input unless there is some */
  267.         if (!timer_sleep(timers, NTIMERS))
  268.             continue;
  269. #endif
  270.         if (fgets(line, sizeof(line), stdin) == NULL)
  271.             break;
  272.         /* Strip trailing CR-LF */
  273.         cp = line + strlen(line) - 1;
  274.         while (cp >= line && (*cp == '\n' || *cp == '\r'))
  275.             *cp-- = '\0';
  276. #ifdef DEBUG
  277.         if (debug)
  278.             syslog(LOG_DEBUG, "<- \"%s\"", line);
  279. #endif
  280.  
  281.         /* Null command */
  282.         if ((argnum = parsit(line, &argp)) == 0)
  283.             continue;
  284.  
  285.         /* a motion to adjourn is always in order */
  286.         if (!strcasecmp(argp[0], "quit"))
  287.             break;
  288.  
  289.         for (i = 0; i < NUMCMDS; ++i)
  290.             if (!strcasecmp(cmdtbl[i].cmd_name, argp[0]))
  291.                 break;
  292.  
  293.         if (i < NUMCMDS) {
  294. #ifdef SETPROCTITLE
  295.             setproctitle("%s %s", hostname, argp[0]);
  296. #endif
  297. #ifdef AUTH
  298.             /* authentication required? */
  299.             if (cmdtbl[i].authreq == 1 && Needauth)
  300.                 {
  301. printf("%d Authentication required for command\r\n", ERR_NOAUTH);
  302.                 (void) fflush(stdout);
  303.                 continue;
  304.                 }
  305. #endif AUTH
  306.             (*cmdtbl[i].cmd_fctn)(argnum, argp);
  307.         } else {
  308. #ifdef SYSLOG
  309.             syslog(LOG_INFO, "%s unrecognized %s", hostname, line);
  310. #endif
  311.             printf("%d Command unrecognized.\r\n", ERR_COMMAND);
  312.             (void) fflush(stdout);
  313.         }
  314.     }
  315.  
  316.     printf("%d %s closing connection.  Goodbye.\r\n", OK_GOODBYE, host);
  317.  
  318.     (void) fflush(stdout);
  319.  
  320. #ifdef BATCHED_INPUT
  321.     batchcheck();
  322. #endif
  323.  
  324. #ifdef SYSLOG
  325.     if (ferror(stdout))
  326.         syslog(LOG_ERR, "%s disconnect: %m", hostname);
  327. #ifdef LOG
  328.     stats_finish();
  329. #endif
  330. #endif
  331.  
  332. #ifdef PROFILE
  333.     profile();
  334. #endif
  335.     exit(0);
  336. }
  337.  
  338. #ifdef TIMEOUT
  339. /*
  340.  * Called after TIMEOUT seconds of idle time to shut things down.
  341.  * XXX stats are not reported when this occurs
  342.  */
  343. static void
  344. timeout()
  345. {
  346.  
  347.     printf("%d Timeout after %d seconds, closing connection.\r\n",
  348.         ERR_FAULT, TIMEOUT);
  349. #ifdef SYSLOG
  350.     syslog(LOG_NOTICE, "%s timeout", hostname);
  351. #endif
  352.     (void) fflush(stdout);
  353. #ifdef BATCHED_INPUT
  354.     batchcheck();
  355. #endif
  356. #ifdef LOG
  357.     stats_finish();
  358. #endif
  359. #ifdef PROFILE
  360.     profile();
  361. #endif
  362.     exit(1);
  363. }
  364. #endif
  365.  
  366. #ifdef LOGINCHECK
  367. /*
  368.  * Called ever LOGINCHECK seconds to see if logins have been disabled.
  369.  * If so, shut down.
  370.  * XXX stats are not reported when this occurs
  371.  */
  372. static void
  373. logincheck()
  374. {
  375.     char host[MAXHOSTNAMELEN];
  376.  
  377.     if (access(NOLOGIN, F_OK) < 0)
  378.         return;
  379.     if (gethostname(host, sizeof(host)) < 0)
  380.         (void) strcpy(host, "Amnesiac");
  381.     printf("%d Logins are disabled on NNTP server %s. Try again later.\r\n",
  382.         ERR_ACCESS, host);
  383.     (void) fflush(stdout);
  384. #ifdef SYSLOG
  385.     syslog(LOG_INFO, "%s logins disabled%s",
  386.         hostname, firstlogincheck ? "" : " (kicked out)");
  387. #endif
  388. #ifdef BATCHED_INPUT
  389.     batchcheck();
  390. #endif
  391. #ifdef LOG
  392.     stats_finish();
  393. #endif
  394. #ifdef PROFILE
  395.     profile();
  396. #endif
  397.     exit(1);
  398. }
  399. #endif
  400.  
  401. #ifdef BATCHED_INPUT
  402. /*
  403.  * Called after BATCHCHECK seconds of idle time and at the end
  404.  * of a session to see if a batch needs to be launched.
  405.  */
  406. static void
  407. batchcheck()
  408. {
  409.     char errbuf[2 * NNTP_STRLEN];
  410.  
  411.     enqpartbatch(CONT_XFER, ERR_XFERFAIL, errbuf);
  412. }
  413. #endif
  414.  
  415. /*
  416.  * Stats stuff
  417.  */
  418. static double        Tstart, Tfinish;
  419. static double        user, sys;
  420. #ifdef USG
  421. static time_t        start, finish;
  422. #else /* not USG */
  423. static struct timeval    start, finish;
  424. #endif /* not USG */
  425.  
  426. static char *
  427. stats_init()
  428. {
  429.     extern char    *ctime();
  430.  
  431. #ifdef USG
  432.     (void) time(&start);
  433.     Tstart = (double) start;
  434.     return(ctime(&start));
  435. #else /* not USG */
  436.     (void) gettimeofday(&start, (struct timezone *)NULL);
  437.     Tstart = (double) start.tv_sec + ((double)start.tv_usec)/1000000.0;
  438.     return(ctime(&start.tv_sec));
  439. #endif /* not USG */
  440. }
  441.  
  442. #ifdef LOG
  443. static void
  444. stats_finish()
  445. {
  446.     char        buf[NNTP_STRLEN];
  447. # ifdef USG
  448.     struct tms    cpu;
  449. # else /* not USG */
  450.     struct rusage    me, kids;
  451. # endif /* not USG */
  452.  
  453. #ifdef USG
  454.     (void) time(&finish);
  455.     Tfinish = (double) finish;
  456.  
  457. #ifndef HZ
  458. #define    HZ    60.0    /* typical system clock ticks - param.h */
  459. #endif /* not HZ */
  460.  
  461.     (void) times(&cpu);
  462.     user = (double)(cpu.tms_utime + cpu.tms_cutime) / HZ;
  463.     sys  = (double)(cpu.tms_stime + cpu.tms_cstime) / HZ;
  464. #else /* not USG */
  465.     (void) gettimeofday(&finish, (struct timezone *)NULL);
  466.     Tfinish = (double) finish.tv_sec + ((double)finish.tv_usec)/1000000.0;
  467.  
  468.     (void) getrusage(RUSAGE_SELF, &me);
  469.     (void) getrusage(RUSAGE_CHILDREN, &kids);
  470.  
  471.     user = (double) me.ru_utime.tv_sec + me.ru_utime.tv_usec/1000000.0 +
  472.         kids.ru_utime.tv_sec + kids.ru_utime.tv_usec/1000000.0;
  473.     sys = (double) me.ru_stime.tv_sec + me.ru_stime.tv_usec/1000000.0 +
  474.         kids.ru_stime.tv_sec + kids.ru_stime.tv_usec/1000000.0;
  475. #endif /* not USG */
  476.     if (grps_acsd)
  477.         syslog(LOG_INFO, "%s exit %d articles %d groups",
  478.             hostname, arts_acsd, grps_acsd);
  479.     if (nn_told)
  480.         syslog(LOG_INFO, "%s newnews_stats told %d took %d",
  481.             hostname, nn_told, nn_took);
  482.     if (ih_accepted || ih_rejected || ih_failed)
  483.         syslog(LOG_INFO,
  484.             "%s ihave_stats accepted %d rejected %d failed %d",
  485.             hostname,
  486.             ih_accepted,
  487.             ih_rejected,
  488.             ih_failed);
  489.     (void) sprintf(buf, "user %.3f system %.3f elapsed %.3f",
  490.         user, sys, Tfinish - Tstart);
  491.     syslog(LOG_INFO, "%s times %s", hostname, buf);
  492. }
  493. #endif LOG
  494.